#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>
#include <stdlib.h>
#include "postData_qt.h"
#include <time.h>

// 上报模式
int type = 0;
int period = 0;

// mqtt
char mqttServerIP[32] = "";
int mqttPort = 0;
char mqttAddr[64] = "";

MQTTClient client;
MQTTClient_connectOptions conn_opts = MQTTClient_connectOptions_initializer;
MQTTClient_message pubmsg = MQTTClient_message_initializer;
MQTTClient_deliveryToken token;

// 共享内存
int *p = NULL;

// 数据库
sqlite3 *db;
char *errmsg = NULL;

// 配置文件
char configBuf[2048] = "";

// 内核链表
struct list_head head;

// 数据存储线程接口
void *sqlHandler()
{
    while (1)
    {
        char sql[128] = "";
        time_t current_time;
        struct tm *time_info;
        // 获取当前时间的秒数，从1970年1月1日00:00:00 UTC起算
        time(&current_time);
        struct std_node *st = (struct std_node *)(p + 1);
        for (int i = 0; i < *p; i++)
        {
            sprintf(sql, "insert into data values(%d,%f,%ld);", st->key, st->new_val.f_val, current_time);
            if (sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK)
            {
                fprintf(stderr, "insert table data err:%s\n", errmsg);
                return -1;
            }
            st++;
        }
        sleep(300);
    }
}
// 数据上报
void mqttPostDataFunc(struct std_node *st, MQTTClient client, MQTTClient_message pubmsg, MQTTClient_deliveryToken token)
{
    cJSON *root = cJSON_CreateObject();
    cJSON_AddItemToObject(root, "type", cJSON_CreateNumber(type));
    cJSON_AddItemToObject(root, "result", cJSON_CreateNumber(0));
    cJSON *data = cJSON_CreateArray();
    for (int i = 0; i < DEVNUM; i++)
    {
        cJSON *item = cJSON_CreateObject();
        if (type == 1)
        {
            if (st->new_val.b_val == st->old_val.b_val || st->new_val.i_val == st->old_val.i_val || st->new_val.f_val == st->old_val.f_val)
            {
                st++;
                continue;
            }
        }
        cJSON_AddItemToObject(item, "key", cJSON_CreateNumber(st->key));
        char num[32] = "";
        switch (st->type)
        {
        case 1:
            sprintf(num, "%d", st->new_val.b_val);
            break;
        case 2:
            sprintf(num, "%d", st->new_val.i_val);
            break;
        case 3:
            sprintf(num, "%.2f", st->new_val.f_val);
            break;
        default:
            break;
        }
        cJSON_AddItemToObject(item, "val", cJSON_CreateString(num));
        cJSON_AddItemToArray(data, item);
        st->old_val = st->new_val;
        st++;
    }
    cJSON_AddItemToObject(root, "data", data);
    char *msg = cJSON_Print(root);
    pubmsg.payload = msg;
    pubmsg.payloadlen = (int)strlen(msg);
    pubmsg.qos = QOS;
    pubmsg.retained = 0;
    // 上报数据,注意修改发布主题
    MQTTClient_publishMessage(client, TOPIC_SE, &pubmsg, &token);
    printf("发布成功\n");
}

volatile MQTTClient_deliveryToken deliveredtoken;

void delivered(void *context, MQTTClient_deliveryToken dt)
{
    printf("Message with token value %d delivery confirmed\n", dt);
    deliveredtoken = dt;
}
// 指令处理
int msgarrvd(void *context, char *topicName, int topicLen, MQTTClient_message *message)
{
    int i;
    char *payloadptr;
    payloadptr = message->payload;
    printf("%s\n", payloadptr);
    cJSON *msgroot = cJSON_Parse(payloadptr);
    int typeNum = cJSON_GetObjectItem(msgroot, "type")->valueint;
    struct std_node *mod = (struct std_node *)(p + 1);
    if (typeNum == 1) // 刷新上报
    {
        mqttPostDataFunc(mod, client, pubmsg, token);
        printf("数据采集发送完成!!!\n");
    }
    else if (typeNum == 2) // 指令控制
    {
        int key = cJSON_GetObjectItem(cJSON_GetObjectItem(msgroot, "data"), "key")->valueint;
        char *val = cJSON_GetObjectItem(cJSON_GetObjectItem(msgroot, "data"), "val")->valuestring;
        cJSON *writeroot = cJSON_CreateObject();
        cJSON_AddItemToObject(writeroot, "key", cJSON_CreateNumber(key));
        // 遍历内核链表，找到数据类型，放入消息队列
        struct list_head *pos;
        struct keyFromJson *tmp;
        list_for_each(pos, &head)
        {
            // 获取节点的数据域地址
            tmp = list_entry(pos, struct keyFromJson, list);
            if (tmp->key == key)
            {
                switch (tmp->type)
                {
                case 1:
                case 2:
                    cJSON_AddItemToObject(writeroot, "val", cJSON_CreateNumber(atoi(val)));
                    break;
                case 3:
                    cJSON_AddItemToObject(writeroot, "val", cJSON_CreateNumber(atof(val)));
                    break;
                default:
                    break;
                }
                break;
            }
        }
        char *magPtr = cJSON_Print(writeroot);
        printf("%s\n", magPtr);
        struct std_node *st = (struct std_node *)(p + 1);
        int type;
        for (int i = 0; i < *p; i++)
        {
            if (st->key == key)
            {
                type = st->dev_type;
            }
            st++;
        }
        struct msg m ;
        m.type = 32;
        strcpy(m.buf,magPtr);
        msg_queue_send("msg", &m, sizeof(m), 0);
        m.type = 502;
        msg_queue_send("msg", &m, sizeof(m), 0);
        printf("控制指令发送完成!!!\n");
    }
    else if (typeNum == 3) // 模式修改
    {
        cJSON *writeroot = cJSON_Parse(configBuf);
        cJSON_SetIntValue(cJSON_GetObjectItem(cJSON_GetObjectItem(writeroot, "report"), "type"), cJSON_GetObjectItem(cJSON_GetObjectItem(msgroot, "data"), "type")->valueint);
        cJSON_SetIntValue(cJSON_GetObjectItem(cJSON_GetObjectItem(writeroot, "report"), "period"), cJSON_GetObjectItem(cJSON_GetObjectItem(msgroot, "data"), "period")->valueint);
        strcpy(configBuf, cJSON_Print(writeroot));
        FILE *fd = fopen(CONFIG_PATH, "r+");
        if (fd == NULL)
        {
            printf("open file error----------%d\n", __LINE__);
            return -1;
        }
        fwrite(configBuf, strlen(configBuf), 1, fd);
        fclose(fd);
        printf("模式修改完成，重启后生效!!!\n");
    }
    else if (typeNum == 4) // 历史记录
    {
        int key = cJSON_GetObjectItem(cJSON_GetObjectItem(msgroot, "data"), "key")->valueint;
        cJSON *limit = cJSON_GetObjectItem(msgroot, "limit");
        int start = cJSON_GetArrayItem(limit, 0)->valueint;
        int end = cJSON_GetArrayItem(limit, 0)->valueint;
        char **result = NULL;
        int hang, lie, k = 0;
        char *sql = NULL;
        cJSON *msgRoot = cJSON_CreateObject();
        cJSON_AddItemToObject(msgRoot, "type", cJSON_CreateNumber(4));
        cJSON_AddItemToObject(msgRoot, "result", cJSON_CreateNumber(0));
        cJSON_AddItemToObject(msgRoot, "key", cJSON_CreateNumber(key));
        cJSON *data = cJSON_CreateArray();
        cJSON_AddItemToObject(msgRoot, "data", data);
        for (int i = start; i <= end; i++)
        {
            sprintf(sql, "select val from data where key=%d and time= %d;", key, i);
            if (sqlite3_get_table(db, sql, &result, &hang, &lie, &errmsg) != SQLITE_OK)
            {
                fprintf(stderr, "select err:%s\n", errmsg);
                return -1;
            }
            for (int i = 0; i <= hang; i++)
            {
                for (int j = 0; j < lie; j++)
                {
                    if (k >= lie)
                    {
                        cJSON *item = cJSON_CreateObject();
                        cJSON_AddItemToObject(item, "time", cJSON_CreateNumber(i));
                        cJSON_AddItemToObject(item, "val", cJSON_CreateString(result[k]));
                        cJSON_AddItemToArray(data, item);
                    }
                    k++;
                }
            }
        }
        char *msg = cJSON_Print(msgRoot);
        pubmsg.payload = msg;
        pubmsg.payloadlen = (int)strlen(msg);
        pubmsg.qos = QOS;
        pubmsg.retained = 0;
        // 上报数据,注意修改发布主题
        MQTTClient_publishMessage(client, TOPIC_SE, &pubmsg, &token);
    }
    MQTTClient_freeMessage(&message);
    MQTTClient_free(topicName);
    return 1;
}

void connlost(void *context, char *cause)
{
    printf("\nConnection lost\n");
    printf("     cause: %s\n", cause);
}

int main(int argc, char const *argv[])
{
    // 读取配置文件
    FILE *fd = fopen(CONFIG_PATH, "r");
    if (fd == NULL)
    {
        printf("open file error----------%d\n", __LINE__);
        return -1;
    }
    fread(configBuf, sizeof(configBuf), 1, fd);
    fclose(fd);
    // printf("%s\n", configBuf);
    cJSON *root = cJSON_Parse(configBuf);
    cJSON *node = cJSON_GetObjectItem(root, "report");
    cJSON *item = cJSON_GetObjectItem(node, "type");
    type = item->valueint;
    item = cJSON_GetObjectItem(node, "period");
    period = item->valueint;

    node = cJSON_GetObjectItem(root, "mqtt_server");
    item = cJSON_GetObjectItem(node, "addr");
    strcpy(mqttServerIP, item->valuestring);
    item = cJSON_GetObjectItem(node, "port");
    mqttPort = item->valueint;

    sprintf(mqttAddr, "tcp://%s:%d", mqttServerIP, mqttPort);
    printf("%s\n", mqttAddr);
    // 连接mqtt服务器

    int rc;
    MQTTClient_create(&client, mqttAddr, CLIENTID, MQTTCLIENT_PERSISTENCE_NONE, NULL);
    conn_opts.keepAliveInterval = 20;
    conn_opts.cleansession = 1;

    MQTTClient_setCallbacks(client, NULL, connlost, msgarrvd, delivered);
    if ((rc = MQTTClient_connect(client, &conn_opts)) != MQTTCLIENT_SUCCESS)
    {
        printf("Failed to connect, return code %d\n", rc);
        exit(EXIT_FAILURE);
    }
    printf("连接mqtt服务器成功!!!\n");

    // 初始化内核链表
    INIT_LIST_HEAD(&head);

    // 初始化共享内存
    struct shm_param p1;
    shm_init(&p1, "shm", 128);
    p = shm_getaddr(&p1);
    *p = DEVNUM;
    struct std_node *dev = (struct std_node *)(p + 1);

    // 解析点表，映射共享内存
    // stm32设备，因为32设备没有寄存器addr，dev_type固定为32
    node = cJSON_GetObjectItem(root, "stm32");
    cJSON *data = cJSON_GetObjectItem(node, "data");
    for (size_t i = 0; i < cJSON_GetArraySize(data); i++)
    {
        dev->key = cJSON_GetObjectItem(cJSON_GetArrayItem(data, i), "key")->valueint;
        dev->type = cJSON_GetObjectItem(cJSON_GetArrayItem(data, i), "type")->valueint;
        dev->dev_type = 32;
        struct keyFromJson *kfj = (struct keyFromJson *)malloc(sizeof(struct keyFromJson));
        kfj->key = cJSON_GetObjectItem(cJSON_GetArrayItem(data, i), "key")->valueint;
        kfj->type = cJSON_GetObjectItem(cJSON_GetArrayItem(data, i), "type")->valueint;
        list_add(&kfj->list, &head);
        dev++;
    }
    // 判断当前设备key值是否在内核链表中存在，存在跳过，不存在加入共享内存与内核链表
    struct list_head *pos;
    struct keyFromJson *tmp;
    int isbreak = 0;
    // modbus设备
    node = cJSON_GetObjectItem(root, "modbus");
    data = cJSON_GetObjectItem(node, "data");
    for (size_t i = 0; i < cJSON_GetArraySize(data); i++)
    {
        isbreak = 0;
        list_for_each(pos, &head)
        {
            // 获取节点的数据域地址
            tmp = list_entry(pos, struct keyFromJson, list);
            if (tmp->key == cJSON_GetObjectItem(cJSON_GetArrayItem(data, i), "key")->valueint)
            {
                isbreak = 1;
                break;
            }
        }
        if (isbreak)
            continue;
        dev->key = cJSON_GetObjectItem(cJSON_GetArrayItem(data, i), "key")->valueint;
        dev->type = cJSON_GetObjectItem(cJSON_GetArrayItem(data, i), "type")->valueint;
        dev->dev_type = 502;
        struct keyFromJson *kfj = (struct keyFromJson *)malloc(sizeof(struct keyFromJson));
        kfj->key = cJSON_GetObjectItem(cJSON_GetArrayItem(data, i), "key")->valueint;
        kfj->type = cJSON_GetObjectItem(cJSON_GetArrayItem(data, i), "type")->valueint;
        list_add(&kfj->list, &head);
        dev++;
    }
    MQTTClient_subscribe(client, TOPIC_RC, QOS);
    // 创建并初始化数据库

    if (sqlite3_open("../config/edge.db", &db) != SQLITE_OK)
    {
        fprintf(stderr, "sqlite3 open err:%s\n", sqlite3_errmsg(db));
        return -1;
    }
    if (sqlite3_exec(db, "create table data(key int,val float,time int);", NULL, NULL, &errmsg) != SQLITE_OK)
    {
        fprintf(stderr, "create table stu1 err:%s\n", errmsg);
        // return -1;
    }
    printf("create ok\n");
    // 创建线程
    pthread_t tid_sql;
    // 子线程--数据存储
    pthread_create(&tid_sql, NULL, sqlHandler, NULL);
    pthread_detach(tid_sql);
    // 主线程数据上报
    while (1)
    {
        if (type == 0)
            continue;
        struct std_node *mod = (struct std_node *)(p + 1);
        mqttPostDataFunc(mod, client, pubmsg, token);
        if (type == 2)
        {
            sleep(5);
        }
    }
    return 0;
}
